﻿using System;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace HeroldIT.Dnn.JQuery
{
    /// <summary>
    /// Defines a client event handler function.
    /// </summary>
    public class ClientEventHandler
    {
        #region static fields

        private static readonly Regex placeholderRegex = new Regex(@"\{\d+\}", RegexOptions.Compiled | RegexOptions.CultureInvariant);

        #endregion

        #region properties

        private string[] Signature { get; set; }

        /// <summary>
        /// Gets the function body of the client event handler.
        /// </summary>
        public string FunctionBody { get; private set; }

        #endregion

        #region constructors

        /// <summary>
        /// Creates a <see cref="ClientEventHandler"/> with the given signature and function body.
        /// </summary>
        /// <param name="signature">The signature for the client event handler. Multiple parameters are separated by the comma character.</param>
        /// <param name="functionBody">The function body for the client event handler.</param>
        /// <param name="formatBody">Whether to replace {0}...{n} placeholders in the <paramref name="functionBody"/>.</param>
        /// <remarks>You can use {0}...{n} placeholders in the <paramref name="functionBody"/> parameter to be replaced with the
        /// corresponding signature member name.</remarks>
        public ClientEventHandler(string signature, string functionBody, bool formatBody = false)
        {
            if (functionBody == null)
                throw new ArgumentNullException("functionBody");
            if (signature == null)
                throw new ArgumentNullException("signature");

            this.Signature = signature.Split(',').Select(arg => arg.Trim()).ToArray();
            this.FunctionBody = formatBody
                                    ? placeholderRegex.Replace(
                                        functionBody,
                                        m => this.Signature[int.Parse(
                                            m.Value.Substring(1, m.Value.Length - 2),
                                            NumberStyles.None,
                                            CultureInfo.InvariantCulture)])
                                    : functionBody;
        }

        /// <summary>
        /// Creates a <see cref="ClientEventHandler"/> with the given signature and function body.
        /// </summary>
        /// <param name="signature">The signature for the client event handler.</param>
        /// <param name="functionBody">The function body for the client event handler.</param>
        /// <param name="formatBody">Whether to replace {0}...{n} placeholders in the <paramref name="functionBody"/>.</param>
        /// <remarks>You can use {0}...{n} placeholders in the <paramref name="functionBody"/> parameter to be replaced with the
        /// corresponding signature member name.</remarks>
        public ClientEventHandler(string[] signature, string functionBody, bool formatBody = false)
        {
            if (functionBody == null)
                throw new ArgumentNullException("functionBody");
            if (signature == null)
                throw new ArgumentNullException("signature");

            this.Signature = signature;
            this.FunctionBody = formatBody
                                    ? placeholderRegex.Replace(
                                        functionBody,
                                        m => signature[int.Parse(
                                            m.Value.Substring(1, m.Value.Length - 2),
                                            NumberStyles.None,
                                            CultureInfo.InvariantCulture)])
                                    : functionBody;
        }

        /// <summary>
        /// Creates a new <see cref="ClientEventHandler"/> with function code prepended to an
        /// existing <see cref="ClientEventHandler"/>.
        /// </summary>
        /// <param name="baseHandler">The existing base <see cref="ClientEventHandler"/>.</param>
        /// <param name="prependBody">The code to prepend to the function body.</param>
        /// <remarks>You can use {0}...{n} placeholders in the <paramref name="prependBody"/> parameter to be replaced with the
        /// corresponding signature member name.</remarks>
        public ClientEventHandler(ClientEventHandler baseHandler, string prependBody)
        {
            if (baseHandler == null)
                throw new ArgumentNullException("baseHandler");
            if (String.IsNullOrEmpty(prependBody))
                throw new ArgumentNullException("prependBody");

            this.Signature = baseHandler.Signature;
            this.FunctionBody =
                placeholderRegex.Replace(
                    prependBody,
                    m => this.Signature[int.Parse(
                        m.Value.Substring(1, m.Value.Length - 2),
                        NumberStyles.None,
                        CultureInfo.InvariantCulture)])
                + baseHandler.FunctionBody;
        }

        #endregion

        #region methods

        /// <summary>
        /// Gets the string representation of this <see cref="ClientEventHandler"/>.
        /// </summary>
        /// <returns>The string representation of this <see cref="ClientEventHandler"/>.</returns>
        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("function(");
            sb.Append(String.Join(",", this.Signature));
            sb.Append("){");
            sb.Append(this.FunctionBody);
            sb.Append("}");
            return sb.ToString();
        }

        #endregion
    }
}
